/***************************************************************
 *  Copyright notice
 *
 *  (c) thomas-p / https://github.com/Thomas-P
 *  (c) sgalinski Internet Services (http://www.sgalinski.de)
 *
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
 *  free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  The GNU General Public License can be found at
 *  http://www.gnu.org/copyleft/gpl.html.
 *
 *  This script is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/

var SG = SG || {};

SG.TinyMceLoader = function(tinymce, options) {
	options = options || {};

	if (!tinymce) {
		return console.error('Couldn\'t load dependency tinyMCE, break here.');
	}

	if (!window.MutationObserver) {
		return console.error('Couldn\'t load dependency MutationObserver, break here.')
	}

	// store original init from the tinyMCE
	this.originalInit = tinymce.init;

	// stores the default options
	this.defaultOptions = options;

	// storage for options
	this.tinyMceOptions = {};

	// selector for tinyMCE
	this.selector = '';

	// initialization flag
	this.firstInit = false;

	this.initialize(options);
};

SG.TinyMceLoader.prototype = {
	/**
	 * Override for the tinyMCE.init. Handle only the options.
	 *
	 * @return {void}
	 */
	initialize: function(options) {
		options = options || {};
		if (this.firstInit) {
			console.error('The tinyMCE loader should only be called once');
		}
		this.firstInit = true;

		// override options with default from extension
		var defaultOptions = this.defaultOptions || {};
		for (var key in defaultOptions) {
			if (defaultOptions.hasOwnProperty(key)) {
				options[key] = defaultOptions[key];
			}
		}

		// override options.setup with own integration
		options.setup = this.setup(options.setup);
		this.tinyMceOptions = options;

		if (options.selector) {
			this.selector = String(options.selector);
		}

		this.setupTinymce(document.body);
		this.initMutationObserver();
	},

	/**
	 * Setup override to manage changes
	 *
	 * @return {function}
	 */
	setup: function(setupMethod) {
		return function(editor) {
			var changeMethod = this.tinyMceOptions.changeMethod;

			if (setupMethod && typeof setupMethod === 'function') {
				setupMethod.call(this, editor);
			}

			editor.on(
				'change', function() {
					if (typeof changeMethod === 'function') {
						var target = editor.targetElm;
						var name = target.name;
						var found = name.match(/^data\[(.*)]\[(.*)]\[(.*)]$/);
						if (found) {
							changeMethod.apply(target, [found[1], found[2], found[3], name]);
						}
					}

					editor.save();
				}
			);
		}.bind(this);
	},

	/**
	 * Automatically apply the tinyMCE editor on new elements
	 *
	 * @return {void}
	 */
	initMutationObserver: function() {
		var observer = new MutationObserver(
			function(mutations) {
				if (!this.selector) {
					return;
				}

				mutations.forEach(
					function(mutation) {
						if (!mutation.target) {
							return;
						}

						this.setupTinymce(mutation.target);
					}.bind(this)
				);
			}.bind(this)
		);

		//noinspection JSCheckFunctionSignatures
		observer.observe(document, {subtree: true, childList: true});
	},

	/**
	 * Setups the tinymce instances for a given element
	 *
	 * @param {Element} element
	 * @return {void}
	 */
	setupTinymce: function(element) {
		var hasMatches = false;
		this.tinyMceOptions.selector = '';

		if (this.selector !== '') {
			var elements = element.querySelectorAll(this.selector);
			for (var index = 0; index < elements.length; ++index) {
				var node = elements[index];

				if (!node.dataset) {
					node.dataset = {};
				}

				if (node.dataset.isTinyMCE) {
					continue;
				}

				// add tinyMCE to node
				if (!node.id) {
					node.id = new Date().getUTCMilliseconds();
				}

				node.dataset.isTinyMCE = true;
				this.tinyMceOptions.selector += ',#' + node.id;
				hasMatches = true;
			}
		}

		if (hasMatches) {
			this.tinyMceOptions.selector = this.tinyMceOptions.selector.slice(1);
			this.originalInit.call(tinymce, this.getTinyMceOptionsAsNewObject());
			document.getElementById('pleasewait' + this.tinyMceOptions.editornumber).style.display = 'none';
		}
	},

	/**
	 * Converts this tinyMceOptions object into a fresh instance of an object.
	 *
	 * @return {string}
	 */
	getTinyMceOptionsAsNewObject: function() {
		var newObject = {};

		for (var key in this.tinyMceOptions) {
			newObject[key] = this.tinyMceOptions[key];
		}

		return newObject;
	}
};